import random
import tkinter
from tkinter import Frame, CENTER, messagebox, Toplevel, Label, Entry, Button
import constants as c
import logic
import request as rq


# 生成0到GRID_LEN-1的随机整数，用于确定新数字的位置
def gen():
    return random.randint(0, c.GRID_LEN - 1)


# 本地的直接赢/输的结果二维矩阵
win_constant = [[1024, 1024, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
lose_constant = [[2, 4, 8, 16], [16, 8, 4, 2], [2, 4, 8, 16], [4, 0, 2, 4]]


class GameGrid(Frame):

    # 初始化游戏界面
    def __init__(self):
        Frame.__init__(self)
        # 使用grid布局管理器
        self.score_label = None
        self.grid()
        # 设置窗口标题
        self.master.title('2048')
        # 用户id
        self.name = 'asdasd'
        # 用户得分
        self.score = 0
        # 是否联网,默认false
        self.online = False
        # 对局是否结束
        self.is_over = False

        # 设置窗口大小
        self.master.geometry("980x600")  # 调整窗口大小以适应左侧信息栏
        self.master.minsize(980, 600)  # 设置窗口最小尺寸
        self.master.resizable(False, False)

        # 绑定键盘事件
        self.master.bind("<Key>", self.key_down)
        # 定义按键命令映射字典
        self.commands = {
            c.KEY_UP: logic.up,
            c.KEY_DOWN: logic.down,
            c.KEY_LEFT: logic.left,
            c.KEY_RIGHT: logic.right,
            c.KEY_UP_ALT1: logic.up,
            c.KEY_DOWN_ALT1: logic.down,
            c.KEY_LEFT_ALT1: logic.left,
            c.KEY_RIGHT_ALT1: logic.right,
            c.KEY_UP_ALT2: logic.up,
            c.KEY_DOWN_ALT2: logic.down,
            c.KEY_LEFT_ALT2: logic.left,
            c.KEY_RIGHT_ALT2: logic.right,
        }

        # 创建主容器
        self.main_container = Frame(self)
        self.main_container.grid(sticky="nsew")

        # 配置行列权重
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        # 左侧信息栏
        # padx: 水平方向的内边距，控制左右两侧的填充空间
        # pady: 垂直方向的内边距，控制上下两侧的填充空间
        self.info_panel = Frame(self.main_container, bg="#bbada0", width=40, padx=5, pady=8)
        self.info_panel.grid(row=0, column=0, sticky="ns")

        # 游戏区域
        self.game_area = Frame(self.main_container)
        self.game_area.grid(row=0, column=1, sticky="nsew")

        # 在信息栏中添加内容
        self.init_info_panel()

        # 存储网格单元格的列表
        self.grid_cells = []
        # 初始化游戏网格
        self.init_grid()
        # 创建新游戏矩阵,一个本地一个请求
        # self.matrix = logic.new_game(c.GRID_LEN)
        self.matrix = rq.new_game(logic.encode_str(self.name))['grid']
        # 历史记录，用于撤销操作
        self.history_matrixs = []
        # 更新网格显示
        self.update_grid_cells()
        # 更新分数显示
        self.update_score()

        # 进入Tkinter主事件循环
        self.mainloop()

    # 初始化信息栏
    def init_info_panel(self):
        self.score_label = Label(self.info_panel, text="分数: 0", bg="#bbada0", fg="white", font=("Arial", 14))
        self.score_label.pack(pady=(0, 10))

        # 名字输入框
        name_frame = Frame(self.info_panel, bg="#bbada0")
        name_frame.pack(fill="x", pady=3)
        Label(name_frame, text="玩家名字:", bg="#bbada0", fg="white", font=("Arial", 10)).pack(anchor="w")

        # self.name_var = tkinter.StringVar(value=name)
        # self.name_entry = Entry(name_frame, textvariable=self.name_var, font=("Arial", 10))
        # self.name_entry.pack(fill="x", pady=2)

        # # 提交名字按钮
        # submit_name_btn = Button(self.info_panel, text="提交名字", command=self.submit_name,
        #                  bg="#8f7a66", fg="white", font=("Arial", 10), padx=3, pady=2)
        # submit_name_btn.pack(fill="x", pady=3)

        # 重新开始游戏按钮
        # restart_btn = Button(self.info_panel, text="重新开始游戏", command=self.restart_game,
        #                  bg="#8f7a66", fg="white", font=("Arial", 10), padx=3, pady=2)
        # restart_btn.pack(fill="x", pady=3)

        # 直接获胜按钮 - 减小按钮大小和内边距
        # padx: 水平方向的内边距（左右填充）
        # pady: 垂直方向的内边距（上下填充）
        win_btn = Button(self.info_panel, text="直接获胜", command=self.trigger_win,
                         bg="#8f7a66", fg="white", font=("Arial", 10), padx=3, pady=2)
        win_btn.pack(fill="x", pady=3)

        # 直接失败按钮 - 减小按钮大小和内边距
        lose_btn = Button(self.info_panel, text="直接失败", command=self.trigger_lose,
                          bg="#8f7a66", fg="white", font=("Arial", 10), padx=3, pady=2)
        lose_btn.pack(fill="x", pady=3)

        # 注册按钮 - 减小按钮大小和内边距
        register_btn = Button(self.info_panel, text="注册", command=self.show_register_popup,
                              bg="#8f7a66", fg="white", font=("Arial", 10), padx=3, pady=2)
        register_btn.pack(fill="x", pady=3)

        # 操作说明 - 减小字体和内边距
        instructions = Frame(self.info_panel, bg="#bbada0")
        instructions.pack(fill="x", pady=(10, 0))
        Label(instructions, text="操作说明:", bg="#bbada0", fg="#ffffff", font=("Verdana", 10, "bold")).pack(anchor="w")
        Label(instructions, text="↑ ↓ ← →: 移动", bg="#bbada0", fg="#ffffff", font=("Verdana", 9)).pack(anchor="w")
        Label(instructions, text="ESC: 退出", bg="#bbada0", fg="#ffffff", font=("Verdana", 9)).pack(anchor="w")

    def submit_name(self):
        new_name = self.name_var.get()
        if not logic.check_string_length(new_name):
            messagebox.showerror("错误", "请输入有效的名字")
            return
        self.name = new_name
        rq.new_game(logic.encode_str(self.name))

    # 直接获胜
    def trigger_win(self):
        try:
            # 发送获胜请求
            if not logic.check_string_length(self.name):
                messagebox.showerror("提示", "未与服务器通信，本地修改结果")
                self.matrix = win_constant
            else:
                en_str = logic.encode_str(self.name)
                resp = rq.isGaming(en_str)
                if resp['grid'] is not None:
                    response = rq.win(en_str)
                    self.matrix = response['grid']
                    self.score = response['score']
            self.update_grid_cells()
        except Exception as e:
            messagebox.showerror("错误", f"网络请求失败: {str(e)}")

    # 间接爽爽失败(
    def trigger_lose(self):
        try:
            # 发送失败请求
            if not logic.check_string_length(self.name):
                messagebox.showerror("提示", "未与服务器通信，本地修改结果")
                self.matrix = lose_constant
            else:
                en_str = logic.encode_str(self.name)
                resp = rq.isGaming(en_str)
                if resp['grid'] is not None:
                    response = rq.lose(en_str)
                    self.matrix = response['grid']
                    self.score = response['score']
            self.update_grid_cells()
        except Exception as e:
            messagebox.showerror("错误", f"网络请求失败: {str(e)}")

    # 显示注册弹窗
    def show_register_popup(self):
        # 创建弹窗
        popup = Toplevel(self)
        popup.title("注册")
        popup.geometry("300x200")
        popup.resizable(False, False)

        # 表单内容
        Label(popup, text="请输入用户名:", font=("Arial", 12)).pack(pady=(20, 5))

        self.name_var = tkinter.StringVar()
        name_entry = Entry(popup, textvariable=self.name_var, font=("Arial", 12))
        name_entry.pack(pady=5)

        # 错误提示标签
        self.error_label = Label(popup, text="", fg="red")
        self.error_label.pack()

        # 按钮框架
        btn_frame = Frame(popup)
        btn_frame.pack(pady=10)

        # 提交按钮
        submit_btn = Button(btn_frame, text="提交", command=lambda: self.submit_register(popup),
                            bg="#8f7a66", fg="white")
        submit_btn.pack(side="left", padx=10)

        # 取消按钮
        cancel_btn = Button(btn_frame, text="取消", command=popup.destroy,
                            bg="#8f7a66", fg="white")
        cancel_btn.pack(side="right", padx=10)

    # 初始化游戏网格界面
    def init_grid(self):
        # 创建背景框架
        background = Frame(self.game_area,
                           bg=c.BACKGROUND_COLOR_GAME,
                           width=c.GAME_SIZE,
                           height=c.GAME_SIZE)
        background.grid()

        # 创建4x4的网格
        for i in range(c.GRID_LEN):
            grid_row = []
            for j in range(c.GRID_LEN):
                # 创建每个单元格的框架
                cell = Frame(
                    background,
                    bg=c.BACKGROUND_COLOR_CELL_EMPTY,
                    width=c.GAME_SIZE / c.GRID_LEN,
                    height=c.GAME_SIZE / c.GRID_LEN
                )
                cell.grid(
                    row=i,
                    column=j,
                    # 水平间距
                    padx=c.GRID_PADDING,
                    # 垂直间距
                    pady=c.GRID_PADDING
                )
                # 创建单元格内的文字标签
                t = Label(
                    master=cell,
                    text="",
                    bg=c.BACKGROUND_COLOR_CELL_EMPTY,
                    # 文字居中
                    justify=CENTER,
                    # 使用预设字体
                    font=c.FONT,
                    width=5,
                    height=2)
                t.grid()
                grid_row.append(t)
            self.grid_cells.append(grid_row)

    # 更新分数显示
    def update_score(self):
        self.score_label.config(text=str(self.score))

        # 这里可以添加获取和更新最高分的逻辑
        # high_score = get_high_score()  # 需要实现这个函数
        # self.high_score_label.config(text=str(high_score))

    # 更新网格单元格显示
    def update_grid_cells(self):
        for i in range(c.GRID_LEN):
            for j in range(c.GRID_LEN):
                new_number = self.matrix[i][j]
                if new_number == 0:
                    # 空白单元格
                    self.grid_cells[i][j].configure(
                        text="",
                        bg=c.BACKGROUND_COLOR_CELL_EMPTY)
                else:
                    # 有数字的单元格
                    self.grid_cells[i][j].configure(
                        text=str(new_number),
                        # 背景色
                        bg=c.BACKGROUND_COLOR_DICT[new_number],
                        # 文字颜色
                        fg=c.CELL_COLOR_DICT[new_number]
                    )
        # 更新分数显示
        self.update_score()
        self.update_idletasks()  # 强制更新界面

    # 键盘交互事件处理
    def key_down(self, event):
        key = event.keysym
        # 退出游戏
        if key == c.KEY_QUIT:
            exit()

        # 处理方向键
        elif key in self.commands:
            self.matrix, done = self.commands[key](self.matrix)
            if done:  # 如果有移动或合并
                print(str(key)[0].lower() + str(key)[1:])
                if len(self.name) != 0:
                    data = rq.move_grid(logic.encode_str(self.name), str(key)[0].lower() + str(key)[1:])
                    self.matrix = data['grid']
                else:
                    self.matrix = logic.add_two(self.matrix)  # 添加新数字
                self.update_grid_cells()

                # 检查游戏状态
                game_state = logic.game_state(self.matrix)
                if game_state == 'win':
                    # 显示胜利信息
                    messagebox.showerror("恭喜!!!", "你获胜了!!!")
                elif game_state == 'lose':
                    # 显示失败信息
                    messagebox.showerror("很遗憾", "挑战结束")

    # 在空白位置生成新数字
    def generate_next(self):
        index = (gen(), gen())
        while self.matrix[index[0]][index[1]] != 0:
            index = (gen(), gen())
        self.matrix[index[0]][index[1]] = 2


# 创建并启动游戏
game_grid = GameGrid()
